import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GamePanel extends JPanel implements KeyListener {
    public static final int CELL_SIZE = 30;
    public static final int ROWS = 20, COLS = 20;
    public char[][] map = new char[ROWS][COLS];
    public BeanList beans = new BeanList();
    public Pacman pacman = new Pacman(1, 1);
    public Ghost ghost = new Ghost(18, 18);
    public int score = 0;
    public boolean gameOver = false;
    private InfoPanel infoPanel;

    public void setInfoPanel(InfoPanel infoPanel) {
        this.infoPanel = infoPanel;
    }

    public GamePanel() {
        setPreferredSize(new Dimension(COLS * CELL_SIZE, ROWS * CELL_SIZE));
        setBackground(Color.BLUE);
        setFocusable(true);
        addKeyListener(this);
        initMap();
    }

    private void initMap() {
        for (int y = 0; y < ROWS; y++)
            for (int x = 0; x < COLS; x++)
                map[y][x] = ' ';
        for (int y = 0; y < ROWS; y++) { map[y][0] = '#'; map[y][COLS-1] = '#'; }
        for (int x = 0; x < COLS; x++) { map[0][x] = '#'; map[ROWS-1][x] = '#'; }
        for (int y = 2; y < ROWS-2; y+=2)
            for (int x = 2; x < COLS-2; x+=2)
                map[y][x] = '#';
        beans = new BeanList();
        for (int y = 1; y < ROWS-1; y++)
            for (int x = 1; x < COLS-1; x++)
                if (map[y][x] != '#')
                    beans.addBean(new Position(x, y));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int y = 0; y < ROWS; y++) {
            for (int x = 0; x < COLS; x++) {
                if (map[y][x] == '#') {
                    g.setColor(Color.BLACK);
                    g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                } else {
                    g.setColor(Color.BLUE);
                    g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                }
            }
        }
        g.setColor(Color.WHITE);
        Bean cur = beans.head;
        while (cur != null) {
            int cx = cur.pos.x * CELL_SIZE + CELL_SIZE/2 - 3;
            int cy = cur.pos.y * CELL_SIZE + CELL_SIZE/2 - 3;
            g.fillOval(cx, cy, 6, 6);
            cur = cur.next;
        }
        g.setColor(Color.YELLOW);
        g.fillArc(pacman.pos.x * CELL_SIZE, pacman.pos.y * CELL_SIZE, CELL_SIZE, CELL_SIZE, 30, 300);
        g.setColor(Color.ORANGE);
        g.fillOval(ghost.pos.x * CELL_SIZE, ghost.pos.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (gameOver) return;
        int dx = 0, dy = 0;
        if (e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP) dy = -1;
        else if (e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN) dy = 1;
        else if (e.getKeyCode() == KeyEvent.VK_A || e.getKeyCode() == KeyEvent.VK_LEFT) dx = -1;
        else if (e.getKeyCode() == KeyEvent.VK_D || e.getKeyCode() == KeyEvent.VK_RIGHT) dx = 1;
        else if (e.getKeyCode() == KeyEvent.VK_Z) { pacman.undo(); repaint(); if (infoPanel != null) infoPanel.repaint(); return; }

        int nx = pacman.pos.x + dx, ny = pacman.pos.y + dy;
        if (map[ny][nx] != '#') {
            pacman.move(dx, dy);
            if (beans.removeBean(pacman.pos)) {
                score += 10;
                if (infoPanel != null) infoPanel.repaint();
            }
        }

        Position next = ghost.nextStep(pacman.pos, map);
        if (next != null) ghost.pos = next;

        if (pacman.pos.equals(ghost.pos)) {
            gameOver = true;
            JOptionPane.showMessageDialog(this, "你被幽灵吃掉了！", "游戏结果", JOptionPane.INFORMATION_MESSAGE);
        }
        if (beans.getCount() == 0) {
            gameOver = true;
            JOptionPane.showMessageDialog(this, "你赢了！", "游戏结果", JOptionPane.INFORMATION_MESSAGE);
        }
        repaint();
        if (infoPanel != null) infoPanel.repaint();
    }
    @Override public void keyReleased(KeyEvent e) {}
    @Override public void keyTyped(KeyEvent e) {}
}